#import "GameScene.h"
#import "SportCarBlue.h"
#import "SportCarRed.h"

#if DEBUG
#import "GLES-Render.h"
#endif


@interface GameScene () <UIGestureRecognizerDelegate> {
    
    UIPanGestureRecognizer *_panGesture;
    
    CCSprite            *_background;
    CCSpriteBatchNode   *_spriteBatch;
    CCTexture2D         *_texture2D;
    
#if DEBUG
    GLESDebugDraw       *_debugDraw;
#endif
    
}

/**
 * Initialize physic engine
 */
- (void)_initPhysics;
/**
 * Initialize child components
 */
- (void)_initSprites;

- (void)_handlePan:(UIPanGestureRecognizer *)gesture;

@end


@implementation GameScene


#pragma mark - Class's static constructors
+ (CCScene *)scene {
    GameScene *rootLayer = [GameScene node];
    CCScene *scene = [CCScene node];
    
    [scene addChild:rootLayer];
    return scene;
}


#pragma mark - Class's constructors
- (id)init {
    self = [super init];
    if (self) {
        _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_handlePan:)];
        [_panGesture setDelegate:self];
        
        _carList = [[NSMutableArray alloc] init];
        
        [self _initPhysics];
        [self _initSprites];
        [self scheduleUpdate];
        
        // Register gesture
        [kAppViewController.view addGestureRecognizer:_panGesture];
    }
    return self;
}


#pragma mark - Cleanup memory
- (void)dealloc {
#if DEBUG
    safeReleaseCPP(_debugDraw);
#endif
    
    safeReleaseCPP(_world);
    safeRelease(_carList);
    
    safeRelease(_background);
    safeRelease(_spriteBatch);
    safeRelease(_texture2D);
    
    [kAppViewController.view removeGestureRecognizer:_panGesture];
    safeRelease(_panGesture);
    [super dealloc];
}


#pragma mark - Class's properties


#pragma mark - Class's public methods
- (void)update:(ccTime)time {
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
    _world->Step(time, velocityIterations, positionIterations);
    
    // Scroll background when there is a moving car
    if ([_carList count] > 0) {
        PhysicSprite *sprite = [_carList objectAtIndex:0];
        if (!sprite.body->IsAwake()) return;
        
        // Get current position
        b2Vec2 currentPosition = sprite.body->GetPosition();
        
        // Calculate the translation
        CGPoint translation = ccp(-currentPosition.x * PTM_RATIO - (kSize.width / 4), currentPosition.y);
        translation = [kDirector convertToGL:translation];
        translation = [self convertToNodeSpace:translation];
        
        CGFloat threshold = (fabsf(self.position.x) + kSize.width) / 2;
        if (fabsf(translation.x) >= threshold) {
            translation.x += threshold;
            [self panForTranslation:translation];
        }
    }
}


#pragma mark - Class's private methods
- (void)_initPhysics {
    // Initialize physic world
	b2Vec2 gravity;
	gravity.Set(0.0f, -0.0f);
	
    _world = new b2World(gravity);
	_world->SetAllowSleeping(true);
	_world->SetContinuousPhysics(true);
    
#if DEBUG
    // Initialize debug draw
    _debugDraw = new GLESDebugDraw(PTM_RATIO);
    _world->SetDebugDraw(_debugDraw);
    
    uint32 flags = 0;
	flags += b2Draw::e_shapeBit;
    flags += b2Draw::e_jointBit;
    flags += b2Draw::e_aabbBit;
    flags += b2Draw::e_pairBit;
    flags += b2Draw::e_centerOfMassBit;
	_debugDraw->SetFlags(flags);
#endif
}
- (void)_initSprites {
    // Initiallize background
    _background = [[CCSprite alloc] initWithFile:@"background.png"];
    [_background setAnchorPoint:CGPointZero];
    [self addChild:_background z:0];
    
    // Initialize sprite
    _spriteBatch = [[CCSpriteBatchNode alloc] initWithFile:@"sportCar.png" capacity:20];
    _texture2D   = [[_spriteBatch texture] retain];
    [self addChild:_spriteBatch z:1];
    
    SportCarBlue *blueCar = [SportCarBlue createWithWorld:_world texture:_texture2D];
    [blueCar setPosition:CGPointMake(10.0f, 60.0f)];
    [blueCar setRotation:-75.0f];
    [_spriteBatch addChild:blueCar];

    SportCarRed *redCar = [SportCarRed createWithWorld:_world texture:_texture2D];
    [redCar setPosition:CGPointMake(400.0f, 80.0f)];
    [_spriteBatch addChild:redCar];
    
    [_carList addObject:blueCar];
    [_carList addObject:redCar];
    
    [blueCar setLinearVelocity:b2Vec2(30.0f, 0.0f)];
}

- (void)panForTranslation:(CGPoint)translation {
//    if (selSprite) {
//        CGPoint newPos = ccpAdd(selSprite.position, translation);
//        selSprite.position = newPos;
//    } else {
        CGPoint newPos = revealPointInsideSprite(_background, self.position, translation);
        self.position = newPos;
//    }
}
//- (void)selectSpriteForTouch:(CGPoint)touchLocation {
//    CCSprite * newSprite = nil;
//    for (CCSprite *sprite in movableSprites) {
//        if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
//            newSprite = sprite;
//            break;
//        }
//    }
//    if (newSprite != selSprite) {
//        [selSprite stopAllActions];
//        [selSprite runAction:[CCRotateTo actionWithDuration:0.1 angle:0]];
//        CCRotateTo * rotLeft = [CCRotateBy actionWithDuration:0.1 angle:-4.0];
//        CCRotateTo * rotCenter = [CCRotateBy actionWithDuration:0.1 angle:0.0];
//        CCRotateTo * rotRight = [CCRotateBy actionWithDuration:0.1 angle:4.0];
//        CCSequence * rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil];
//        [newSprite runAction:[CCRepeatForever actionWithAction:rotSeq]];
//        selSprite = newSprite;
//    }
//}

- (void)_handlePan:(UIPanGestureRecognizer *)gesture {
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan: {
            CGPoint location = [gesture locationInView:gesture.view];
            location = [kDirector convertToGL:location];
            location = [self convertToNodeSpace:location];
//            [self selectSpriteForTouch:location];
            break;
        }
            
        case UIGestureRecognizerStateEnded: {
            [self stopAllActions];
            CGPoint velocity = [gesture velocityInView:gesture.view];
            CGPoint newPos   = revealPointInsideSprite(_background, self.position, ccpMult(velocity, kScrollDuration));
            
            CCMoveTo *moveTo = [CCMoveTo actionWithDuration:kScrollDuration position:newPos];
            [self runAction:[CCEaseOut actionWithAction:moveTo rate:1.0f]];
            break;
        }
            
        case UIGestureRecognizerStateChanged:
        default:
            CGPoint translation = [gesture translationInView:gesture.view];
            translation.y *= -1.0f; // Cocos2d coordinate system different with UIKit coordinate system
            
            [self panForTranslation:translation];
            break;
    }
    [gesture setTranslation:CGPointZero inView:gesture.view];
}


#pragma mark - UIGestureRecognizerDelegate's members
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    return YES;
}


@end
